
#include "./window.hpp"

namespace yisc { namespace gui { namespace win32 {

  char const * const window::s_className = "yisc::gui::window";
  window::window_atom_t window::s_winAtom = NULL;
  HINSTANCE window::module_instance_ = 0;

  void window::module_instance( HINSTANCE h ) { module_instance_ = h; }
  HINSTANCE window::module_instance() { return module_instance_; }

  bool window::register_window_atom_s()
  {
    if ( NULL == s_winAtom ) {
      // TODO: set mutex here 
      if ( NULL == s_winAtom ) {
        ::WNDCLASSEX winClass;

        winClass.cbSize = sizeof(winClass);
        winClass.style = CLASS_STYLE;
        winClass.lpfnWndProc = &window::handle_nccreate_s; //window_procedure_s;
        winClass.cbClsExtra = 0;
        winClass.cbWndExtra = 0;
        winClass.hInstance = module_instance(); //::GetModuleHandle(NULL);
        winClass.hIcon = ::LoadIcon(NULL, IDI_APPLICATION);
        winClass.hCursor = ::LoadIcon(NULL, IDC_ARROW);
        winClass.hbrBackground = (HBRUSH)::GetStockObject(WHITE_BRUSH); //(HBRUSH)(COLOR_BACKGROUND+1);
        winClass.lpszMenuName = NULL;
        winClass.lpszClassName = "yisc::gui::window";//s_className;
        winClass.hIconSm = NULL;
    
        s_winAtom = ::RegisterClassEx(&winClass);
        assert( s_winAtom != 0 );
      }
    }
    return (s_winAtom != 0);
  }

  LRESULT CALLBACK window
  ::handle_nccreate_s( handle_t hWnd, msg_t uMsg, WPARAM wPara, LPARAM lPara)
  {
    std::cout<<__FUNCTION__<<": "<<uMsg<<std::endl;

    window *w = 0;

    if ( WM_NCCREATE == uMsg ) {
      w = reinterpret_cast<window*>(((LPCREATESTRUCT)lPara)->lpCreateParams);
      assert( w != 0 );

      ::SetWindowLongPtr(hWnd, GWL_USERDATA, reinterpret_cast<LONG_PTR>(w));

      ::SetWindowLongPtr(hWnd, GWL_WNDPROC, (LONG_PTR)&window::window_procedure_s);

      std::cout<<__FUNCTION__<<":window: "<<hWnd<<std::endl;
      w->handle_ = hWnd;

//       yisc::gui::window::message_t msg = make_msg(uMsg, wPara, lPara);
//       return w->on_message( msg );
      return true;
    }
    else {
      // TODO: fatal error
      std::cerr<<"fatal:message: "<<uMsg<<std::endl;
    }

    return ::DefWindowProc( hWnd, uMsg, wPara, lPara );
  }

  LRESULT CALLBACK window
  ::window_procedure_s( handle_t hWnd, msg_t uMsg, WPARAM wPara, LPARAM lPara)
  {
    std::cout<<__FUNCTION__<<":message: "<<uMsg<<std::endl;

    window *w = reinterpret_cast<window*>(GetWindowLongPtr(hWnd, GWL_USERDATA));
    assert( w != 0 );

    yisc::gui::window::message_t msg = make_msg(uMsg, wPara, lPara);
    if ( w->on_message( msg ) )
      return S_OK;

    return ::DefWindowProc( w->handle_, uMsg, wPara, lPara );
  }

  window::window()
  {
  }

  window::~window()
  {
  }

  bool window::create()
  {
    if ( !register_window_atom_s() )
      return false;

    //handle_ =
      ::CreateWindowEx
      (
       WINDOW_STYLE_EX,
       "yisc::gui::window",//s_className,
       "my window", // title-bar string
       WINDOW_STYLE,
       CW_USEDEFAULT,
       CW_USEDEFAULT,
       CW_USEDEFAULT,
       CW_USEDEFAULT,
       NULL, /* hwndParent */
       NULL, /* hMenu */
       module_instance(), //::GetModuleHandle(NULL), /* hInstance */
       (LPVOID)this // window-creation data
       );

    std::cout<<"error: "<<::GetLastError()<<std::endl;
    std::cout<<"module: "<<module_instance()<<", "<<::GetModuleHandle(NULL)<<std::endl;
    std::cout<<"handle: "<<handle_<<std::endl;
    
    return ( NULL != handle_ );
  }

  void window::show()
  {
    ::ShowWindow(handle_, SW_SHOW);
  }

  void window::update()
  {
    ::UpdateWindow(handle_);
  }

  bool window::on_message( message_t& msg )
  {
    return false;
  }

  bool window::message_loop()
  {
    bool result = false;
    BOOL r;
    MSG m;

    while( ((r = ::GetMessage( &m, NULL, 0, 0 )) != 0) && (r != -1) ) {
      //if ( ::IsWindow(handle_) ) { //||
      //!::IsDialogMessage(handle_, &m) ) {
      ::TranslateMessage( &m );
      ::DispatchMessage( &m );
      //}
    }
    
    return result;
  }
    
}//namespace win32
}//namespace gui
}//namespace yisc


